package com.wei.web.middleware.httpfilter.registrar.security;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wei.web.middleware.httpfilter.auth.security.SecurityFilterChainFactoryBean;
import com.wei.web.middleware.httpfilter.auth.security.SpringSecurityStarter;
import com.wei.web.middleware.httpfilter.auth.security.WebSecurityCustomizerFactoryBean;
import com.wei.web.middleware.httpfilter.auth.security.model.SecurityConfigDTO;
import com.wei.web.middleware.httpfilter.exceptions.FASException;
import com.wei.web.middleware.httpfilter.registrar.IRegistrar;
import com.wei.web.middleware.httpfilter.registrar.WebFilterRegistrarManager;
import com.wei.web.middleware.httpfilter.registrar.model.FilterConfigDTO;
import com.wei.web.middleware.httpfilter.registrar.model.RegisterContext;
import com.wei.web.middleware.httpfilter.utils.FileUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;

public class SecurityAuthRegistrar implements IRegistrar {

    public static final String RESOURCE_LOCATION = "auth/security_config.json";

    public static final String TYPE = "securityAuth";

    @Override
    public String getType() {
        return TYPE;
    }

    @SneakyThrows
    @Override
    public void registrar(FilterConfigDTO filterConfigDTO, BeanDefinitionRegistry registry, RegisterContext registerContext) {
        SecurityConfigDTO securityConfigDTO = null;
        try {
            securityConfigDTO = getSecurityConfig(filterConfigDTO);
        } catch (IOException e) {
            throw e;
        }

        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(SpringSecurityStarter.class);
        String name = filterConfigDTO.getName();
        if (StringUtils.isEmpty(name)) {
            name = SpringSecurityStarter.class.getName()+registerContext.getFilterOrder();
        }
        registry.registerBeanDefinition(name, builder1.getBeanDefinition());

        doRegisterWebSecurityCustomizer(registry, securityConfigDTO.getIgnoreUrls());

        Integer securityFilterChainIndex = 1;
        for (SecurityConfigDTO.AuthConfigDTO authConfigDTO : securityConfigDTO.getAuthList()) {
            doRegisterSecurityFilterChain(registry,
                    authConfigDTO,
                    securityFilterChainIndex);
            securityFilterChainIndex++;
        }

    }

    private void doRegisterWebSecurityCustomizer(BeanDefinitionRegistry registry, List<String> ignoreUrls) {
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(WebSecurityCustomizerFactoryBean.class);
        builder1.addConstructorArgValue(ignoreUrls.toArray(new String[0]));
        String beanName = "webSecurityCustomizer";
        registry.registerBeanDefinition(beanName, builder1.getBeanDefinition());
    }

    private void doRegisterSecurityFilterChain(BeanDefinitionRegistry registry,
                                               SecurityConfigDTO.AuthConfigDTO authConfigDTO,
                                               Integer securityFilterChainIndex) {
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(SecurityFilterChainFactoryBean.class);
        builder1.addPropertyValue("authConfig", authConfigDTO);
        builder1.addAutowiredProperty("http");
        String beanName = "securityFilterChainFactoryBean" + securityFilterChainIndex;
        registry.registerBeanDefinition(beanName, builder1.getBeanDefinition());
    }

    private SecurityConfigDTO getSecurityConfig(FilterConfigDTO filterConfigDTO) throws IOException {
        ClassLoader classLoader = SecurityAuthRegistrar.class.getClassLoader();
        String configStr = FileUtil.getContent(getConfigLocation(filterConfigDTO), classLoader);
        SecurityConfigDTO securityConfigDTO = JSONObject.parseObject(configStr, new TypeReference<>() {});
        return securityConfigDTO;
    }

    private String getConfigLocation(FilterConfigDTO filterConfigDTO) {
        String configFilePath = filterConfigDTO.getConfig().get("config_file").toString().trim();
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(configFilePath)) {
            return configFilePath;
        }
        return RESOURCE_LOCATION;
    }
}
